package unsafe

import (
	"errors"
	"reflect"
	"unsafe"
)

type UnsafeAccessor struct {
	address unsafe.Pointer // 对象的起始地址用指针
	fields  map[string]FieldMeta
}

type FieldMeta struct {
	Offset uintptr // 字段的偏移量使用uintptr
	typ    reflect.Type
}

// NewUnsafeAccessor entity 只支持传一级结构体指针
func NewUnsafeAccessor(entity any) *UnsafeAccessor {
	typeOf := reflect.TypeOf(entity).Elem()
	numField := typeOf.NumField()
	fields := make(map[string]FieldMeta, numField)
	for i := 0; i < numField; i++ {
		field := typeOf.Field(i)
		fields[field.Name] = FieldMeta{
			Offset: field.Offset,
			typ:    field.Type,
		}
	}
	val := reflect.ValueOf(entity)
	return &UnsafeAccessor{
		fields:  fields,
		address: val.UnsafePointer(),
	}

}

// Field unsafe 读取字段 struct 某个字段的地址等于：起始地址 + 字段偏移量
func (u *UnsafeAccessor) Field(field string) (any, error) {
	fd, ok := u.fields[field]
	if !ok {
		return nil, errors.New("非法字段")
	}
	// 字段起始地址
	fdAddress := unsafe.Pointer(uintptr(u.address) + fd.Offset)
	// 如果知道类型，就这么读
	// return *(*int)(fdAddress), nil
	// 不知道确切类型
	return reflect.NewAt(fd.typ, fdAddress).Elem().Interface(), nil
}

// SetField unsafe 设置/修改字段 struct 某个字段的地址等于：起始地址 + 字段偏移量
func (u *UnsafeAccessor) SetField(field string, val any) error {
	// 起始地址 + 字段偏移量
	fd, ok := u.fields[field]
	if !ok {
		return errors.New("非法字段")
	}
	// 字段起始地址
	fdAddress := unsafe.Pointer(uintptr(u.address) + fd.Offset)
	// 确切类型就这么写
	// *(*int)(fdAddress) = val.(int)

	// 你不知道确切类型
	reflect.NewAt(fd.typ, fdAddress).Elem().Set(reflect.ValueOf(val))
	return nil
}
